EFSアクセスポイントのルートディレクトリ作成のアクセス許可とPOSIXユーザー指定を試してみた
みなさんこんにちは、杉金です。
EFSアクセスポイントのオプション設定である、ルートディレクトリ作成のアクセス許可とPOSIXユーザー指定を試してみます。
試そうと思ったきっかけは、AWS Security Hubに追加されたコントロールEFS.3とEFS.4で、ルートディレクトリの適用やユーザーID指定を推奨しています。EFSアクセスポイントのこれらのオプション設定って何なのか、実際に試していきます。
まず結論から
アクセスポイントのルートディレクトリとは
アクセスポイントの設定でルートディレクトリを指定できますが、これはアクセスポイントをアタッチ(マウント)するときのEFS側のディレクトリを指します。イメージ図を描いてみました。
ルートディレクトリを指定をしない場合は、「/」がルートディレクトリになります。EFS.3では、デフォルトの「/」は非推奨としています。利用ケースにより「/」を使用したい場合もありそうですが、不必要なアクセスを避けるためにもルートディレクトリは「/」以外で設定しておくことをオススメします。
ルートディレクトリの設定オプションとして「ルートディレクトリ作成のアクセス許可」というものがあります。これはルートディレクトリが存在しない場合に指定した権限(所有ユーザ、所有グループ、パーミッション)でディレクトリを作成してくれるものです。既にディレクトリが存在する場合は何もせず、権限上書きもしません。まだルートディレクトリが存在しない場合にこのオプションを指定するとよいでしょう。
POSIXユーザーの指定
こちらも同様にイメージ図を描いてみました。このオプションですが、アクセスポイントでPOSIXユーザーを指定することで、接続元のユーザーに関わらずアクセスポイントで指定するユーザー情報でアクセスされます。
上の図では3種類のユーザーがアクセスポイント経由でアクセスしていますが、どのユーザーのアクセスでもアクセスポイントで指定するユーザーID:151、グループID:150でアクセスされます。そのため、アクセスポイントで指定するユーザーがアクセスできるファイルやディレクトリにのみアクセスが許可されます。
たとえば、user2はfile3にアクセスできる権限を持っていますが、アクセスポイントを経由してアクセスするとユーザー情報が置き換わり、user2であってもアクセスはできません。
この設定はオプションですので、指定しない場合は接続元のユーザー情報でアクセスされます。アクセスポイントでユーザーを指定することで、アクセス元の権限を意識する必要がなくなります。LambdaからEFSのアクセスポイントにアクセスするにはPOSIXユーザー指定はやっておくべきです。その理由は本記事後半で記載します。Lambdaでの設定に関する参考リンクを記載します。
Lambda 関数を使用してファイルシステムをマウントするための正しい EFS アクセスポイント構成を作成するにはどうすればよいですか?
Lambda 関数のファイルシステムアクセスの設定-ファイルシステムとアクセスポイントの設定
セカンダリグループIDの指定
POSIXユーザーの指定には、セカンダリグループIDの指定もできます。セカンダリグループを指定することでアクセス可能な範囲を広げられます。下の図ではセカンダリグループIDに350を指定することで、file4へのアクセスが可能になります。
セカンダリグループIDの使いどころとしては、共通のログや設定ファイル置き場などへのアクセス範囲を広げるようなケースでの利用が思いつきます。セカンダリグループIDはカンマ区切りで複数指定可能です。
たとえばこれがファイルではなくディレクトリの場合、セカンダリグループに書き込み権限のあるディレクトリ配下にファイルを作るとどのような所有者権限で作成されるのか。答えとしては、アクセスポイントで指定するユーザーIDとグループIDでファイルが作成されます。
設定箇所はどこか
先に結論を書きましたが、そもそもEFSアクセスポイントを使ったことのない方にもイメージがつくよう、マネジメントコンソールの設定箇所を紹介します。まず、アクセスポイントはEFSの左側にあるメニューからアクセスできます。
作成画面の最初に基本となる設定があり、ここでルートディレクトリを指定できます。
設定項目としては次の3つです。
- ファイルシステム(利用したいEFSファイルシステムをリストから選択)
- アクセスポイントの名前
- ルートディレクトリ
下にスクロールするとオプションとしてPOSIXユーザーを指定する箇所があります。
設定項目としては次の3つです。
- ユーザーID
- グループID
- セカンダリグループID
さらに下にスクロールするとルートディレクトリ作成のアクセス許可設定があります。
設定項目としては次の3つです。
- 所有者ユーザーID
- 所有者グループID
- POSIXアクセス許可
実際に試してみる
それでは実際にAmazon Linux2からEFSへのアクセスで試してみます。次のことを試していきます。
試すこと
- 試すこと1: イメージ図にあるようなPOSIXユーザ指定のアクセス
- 試すこと2: イメージ図にあるようなセカンダリグループID指定のアクセス
- 試すこと3: ルートディレクトリのアクセス許可設定を空欄にするとどうなるか
- 試すこと4: ルートディレクトリ作成オプションが有効な状態でルートディレクトリを消すとどうなるか
下準備1:アクセス元のユーザ用意
ユーザー情報はこんな感じです。
[ec2-user@ip-10-0-0-28 ~]$ id user1; id user2; id user3 uid=151(user1) gid=150(test-group1) groups=150(test-group1) uid=251(user2) gid=250(test-group2) groups=250(test-group2) uid=351(user3) gid=350(test-group3) groups=350(test-group3)
下準備2:アクセスポイント作成
EFSのファイルシステムは作成済みとして、まずはアクセスポイントを作成します。
ファイルシステムは作成済みのファイルシステムを選びます。ルートディレクトリパスは未設定の場合、EFSファイルシステムのルートディレクトリになります。
ユーザー情報を指定します。先ほど紹介したイメージ図と同じような設定を入れます。セカンダリグループは一旦無しで作成します。
ルートディレクトリ作成も指定していきます。
更に下にスクロールして「アクセスポイントの作成」を選択します。
アクセスポイント一覧にアクセスポイントが作成されました。
ルートディレクトリが存在するか見てみます。EFSのファイルシステムをマウントしている領域から確認してみます。
[ec2-user@ip-10-0-0-28 efs]$ ls -l 合計 0
何も存在しませんでした。この機能の面白いところですが、アクセスポイントを作成しただけではアクセスポイント用のルートディレクトリは作成されません。
下準備3:アクセスポイントのアタッチ
アクセスポイントの領域をアタッチします。マネジメントコンソールからアクセスポイントを選択して「詳細の表示」を選択します。
そうすると右上にアタッチというボタンがありますので、それを選択します。
アタッチのコマンドが表示されますのでコピーします。末尾の"efs"はマウント先(マウントポイント)ですので、マウントさせたい場所を指定してください。今回は適当に"/AP1"にマウントします。
sudo mount -t efs -o tls,accesspoint=fsap-XXXXX fs-XXXXX:/ /AP1
アクセスポイントをマウントするとルートディレクトリが作成されました。権限も指定したものですね。
[ec2-user@ip-10-0-0-28 efs]$ ls -l 合計 4 drwxr-xr-x 2 user1 test-group1 6144 9月 13 08:13 accesspoint1
下準備4:テストファイル用意
テストファイルを用意します。
[user1@ip-10-0-0-28 AP1]$ pwd /AP1 [user1@ip-10-0-0-28 AP1]$ ls -l total 16 -rw------- 1 user1 test-group1 43 Sep 13 08:16 file1 ----rw---- 1 user1 test-group1 43 Sep 13 08:16 file2 -rw------- 1 user2 test-group2 43 Sep 13 08:16 file3 ----rw---- 1 user3 test-group3 43 Sep 13 08:16 file4
(所有ユーザーの権限なし、所有グループのみ許可というのは実利用のケースでなさそうですが)
ユーザID、グループIDで表示させるとこんな感じです。
[user1@ip-10-0-0-28 AP1]$ ls -ln total 16 -rw------- 1 151 150 43 Sep 13 08:16 file1 ----rw---- 1 151 150 43 Sep 13 08:16 file2 -rw------- 1 251 250 43 Sep 13 08:16 file3 ----rw---- 1 351 350 43 Sep 13 08:16 file4
試すこと1:POSIXユーザ指定のアクセス
準備ができましたので、イメージ図のようにPOSIXユーザ指定でのアクセスを試していきましょう。user1でdateコマンドをリダイレクトさせてファイルに現在時刻を追記します。
[user1@ip-10-0-0-28 AP1]$ date >> file1 [user1@ip-10-0-0-28 AP1]$ date >> file2 -bash: file2: Permission denied [user1@ip-10-0-0-28 AP1]$ date >> file3 -bash: file3: Permission denied [user1@ip-10-0-0-28 AP1]$ date >> file4 -bash: file4: Permission denied
file1のみ書き込めました。イメージ図と違ってfile2は書き込めないですね。なぜだか理由は分かりますでしょうか。これは所有ユーザーであるuser1(151)に書き込み権限が付与されていないからです。
試しにfile2の所有ユーザーをuser1からuser2に変えて書き込みをしてみましょう。
[user1@ip-10-0-0-28 AP1]$ ls -l file2 ----rw---- 1 user2 test-group1 43 Sep 13 08:44 file2 [user1@ip-10-0-0-28 AP1]$ date >> file2 [user1@ip-10-0-0-28 AP1]$ cat file2 2022年 9月 13日 火曜日 08:44:03 UTC Tue Sep 13 08:50:47 UTC 2022
今度は書き込めました。イメージ図では省略しましたが、ファイルの所有者とパーミッションがアクセス可否を決めます。
アクセスポイント経由であればuser2とuser3もuser1と同様の結果となりますので試します。まずはuser2でアクセスを試します。
[user2@ip-10-0-0-28 AP1]$ ll total 16 -rw------- 1 user1 test-group1 101 Sep 13 09:02 file1 ----rw---- 1 user2 test-group1 101 Sep 13 09:02 file2 -rw------- 1 user2 test-group2 43 Sep 13 09:03 file3 ----rw---- 1 user3 test-group3 43 Sep 13 09:03 file4 [user2@ip-10-0-0-28 AP1]$ date >> file1 [user2@ip-10-0-0-28 AP1]$ date >> file2 [user2@ip-10-0-0-28 AP1]$ date >> file3 -bash: file3: Permission denied [user2@ip-10-0-0-28 AP1]$ date >> file4 -bash: file4: Permission denied
user1と同様にfile1とfile2のみ書き込めました。
user3でアクセスを試します。
[user3@ip-10-0-0-28 AP1]$ ll total 16 -rw------- 1 user1 test-group1 130 Sep 13 09:04 file1 ----rw---- 1 user2 test-group1 130 Sep 13 09:04 file2 -rw------- 1 user2 test-group2 43 Sep 13 09:03 file3 ----rw---- 1 user3 test-group3 43 Sep 13 09:03 file4 [user3@ip-10-0-0-28 AP1]$ date >> file1 [user3@ip-10-0-0-28 AP1]$ date >> file2 [user3@ip-10-0-0-28 AP1]$ date >> file3 -bash: file3: Permission denied [user3@ip-10-0-0-28 AP1]$ date >> file4 -bash: file4: Permission denied
user1とuser2と同様の結果となりました。これがアクセス元のユーザー情報に関係なく、アクセスポイントで指定するユーザー情報でアクセスされる、ということです。もちろんuser1〜3に限らずrootユーザーでも同じ結果です。
試すこと2:セカンダリグループID指定のアクセス
続いてセカンダリグループIDを設定してみましょう。アクセスポイントを再作成してもよいのですが、別のアクセスポイントを作ります。ルートディレクトリは先ほど作成したものと同じ領域を指定します。同じ領域にアクセスするがアクセスポイントは別という形です。
セカンダリグループIDに350を指定します。
アクセスポイントがもうひとつできました。
今度は”/AP2"という領域にマウントします。
sudo mount -t efs -o tls,accesspoint=fsap-XXXXX fs-XXXXX:/ /AP2
user1でアクセスを試します。
total 16 -rw------- 1 user1 test-group1 159 Sep 13 09:05 file1 ----rw---- 1 user2 test-group1 159 Sep 13 09:05 file2 -rw------- 1 user2 test-group2 43 Sep 13 09:03 file3 ----rw---- 1 user3 test-group3 43 Sep 13 09:03 file4 [user1@ip-10-0-0-28 AP2]$ date >> file1 [user1@ip-10-0-0-28 AP2]$ date >> file2 [user1@ip-10-0-0-28 AP2]$ date >> file3 -bash: file3: Permission denied [user1@ip-10-0-0-28 AP2]$ date >> file4 [user1@ip-10-0-0-28 AP2]$ cat file4 2022年 9月 13日 火曜日 09:03:13 UTC Tue Sep 13 09:17:23 UTC 2022 [user1@ip-10-0-0-28 AP2]$ ll total 16 -rw------- 1 user1 test-group1 188 Sep 13 09:17 file1 ----rw---- 1 user2 test-group1 188 Sep 13 09:17 file2 -rw------- 1 user2 test-group2 43 Sep 13 09:03 file3 ----rw---- 1 user3 test-group3 72 Sep 13 09:17 file4 [user1@ip-10-0-0-28 AP2]$
filr4にも書き込めました。user1だけでなくuser2、user3も同様ですのでuser2と3は割愛します。これがセカンダリグループIDの指定です。 ついでに、セカンダリグループIDで許可されたディレクトリ配下にファイルを作ってみましょう。
[root@ip-10-0-0-28 AP2]# ll 合計 4 drwxrwxr-x 2 user3 test-group3 6144 9月 13 10:30 dir1 [root@ip-10-0-0-28 AP2]# date >> dir1/file5 [root@ip-10-0-0-28 AP2]# ll dir1/ 合計 4 -rw-r--r-- 1 user1 test-group1 43 9月 13 10:30 file5
ユーザーはrootですがアクセスポイント経由でアクセスしているため、アクセスポイント指定したユーザー(user1:test-group1)でファイルが作成されます。セカンダリグループIDとして指定しているグループでもグループで書き込み権限を与えればファイルを作成できることが分かりました。
試すこと3:ルートディレクトリのアクセス許可設定を空欄にするとどうなるか
続いての試すことですが、アクセスポイント作成で存在しないルートディレクトリを指定し、その際にルートディレクトリのアクセス許可設定をスキップするとどうなるでしょうか。
存在しない/accesspoint3
を指定します。ルートディレクトリ作成のアクセス許可設定をスキップします。
アクセスポイントの作成は成功しますが、マウント時にマウントできないエラーとなります。
[root@ip-10-0-0-28 ~]# sudo mount -t efs -o tls,accesspoint=fsap-XXXXX fs-XXXXX:/ /AP3 b'mount.nfs4: access denied by server while mounting 127.0.0.1:/'
手動でルートディレクトリaccesspoint3
を作成するとマウントできます。存在しないルートディレクトリ指定する場合は、ルートディレクトリ作成のアクセス許可設定は必須としておくと二度手間がなくなるでしょう。
試すこと4:ルートディレクトリを消すとどうなるか
ここは完全に興味本位のところですが、先ほどのルートディレクトリ作成のアクセス許可設定を行なったaccesspoint1
のディレクトリを消すとどうなるかやってみましょう。
[root@ip-10-0-0-28 efs]# ll 合計 4 drwxr-xr-x 2 user1 test-group1 6144 9月 13 08:16 accesspoint1 [root@ip-10-0-0-28 efs]# rm -rf ./accesspoint1/ [root@ip-10-0-0-28 efs]# ll 合計 0
/AP1
にアクセスするとエラーになります。アンマウントもできません。
[root@ip-10-0-0-28 efs]# cd /AP1 -bash: cd: /AP1: Stale file handle [root@ip-10-0-0-28 efs]# umount /AP1 umount.nfs4: /AP1: device is busy
dfを実行してみると冒頭にエラー出ています。
[root@ip-10-0-0-28 efs]# df -h df: `/AP2': Stale file handle df: `/AP1': Stale file handle ファイルシス サイズ 使用 残り 使用% マウント位置 devtmpfs 468M 0 468M 0% /dev tmpfs 479M 0 479M 0% /dev/shm tmpfs 479M 624K 478M 1% /run tmpfs 479M 0 479M 0% /sys/fs/cgroup /dev/nvme0n1p1 8.0G 1.5G 6.5G 19% / tmpfs 96M 0 96M 0% /run/user/1000 127.0.0.1:/ 8.0E 0 8.0E 0% /efs
当然、マウントしてみると失敗します。
[root@ip-10-0-0-28 efs]# sudo mount -t efs -o tls,accesspoint=fsap-XXXXX fs-XXXXX:/ /AP1 b'mount.nfs4: Stale file handle'
Lazy umountしてから、再度マウントしてみます。
[root@ip-10-0-0-28 efs]# umount -l /AP1 [root@ip-10-0-0-28 efs]# sudo mount -t efs -o tls,accesspoint=fsap-XXXXX fs-XXXXX:/ /AP1 [root@ip-10-0-0-28 efs]# ll 合計 4 drwxr-xr-x 2 user1 test-group1 6144 9月 13 09:50 accesspoint1
マウントできました。AP1のみumountを実行したため、AP2はエラーが出たままになります。
[root@ip-10-0-0-28 efs]# df -h df: `/AP2': Stale file handle ファイルシス サイズ 使用 残り 使用% マウント位置 devtmpfs 468M 0 468M 0% /dev tmpfs 479M 0 479M 0% /dev/shm tmpfs 479M 624K 478M 1% /run tmpfs 479M 0 479M 0% /sys/fs/cgroup /dev/nvme0n1p1 8.0G 1.5G 6.5G 19% / tmpfs 96M 0 96M 0% /run/user/1000 127.0.0.1:/ 8.0E 0 8.0E 0% /efs 127.0.0.1:/ 8.0E 0 8.0E 0% /AP1
マウントすることでルートディレクトリは作成されました。興味本位でやってみましたが、実環境では遭遇したくないものです。
LambdaでEFSを使う設定
LambdaでもEFSは使用できます。Lambdaの設定→ファイルシステムから設定可能です。
ただし、VPCにLambda関数を作成する必要があります。非VPCのLambdaでファイルシステムを作成しようとすると以下のエラーとなります。
ファイルシステムに接続するには、まず、ファイルシステムが実行されている VPC に関数を接続する必要があります。
VPC上にLambda関数を作成するには関数作成時に詳細設定から「VPCを有効化」にチェックを入れて対象となるVPC、サブネット、セキュリティグループを設定していきます。
改めて、設定→ファイシステムから設定します。重要な点としてアクセスポイント指定なしでは作成できません。
LambdaでEFSを使うにはアクセスポイントは必須と覚えましょう。
ちなみに、LambdaでアクセスポイントのPOSIXユーザー指定をしないとどのような権限で書き込まれるのでしょうか。以下のPythonコードで書き込みテストをしてみます。
import json def lambda_handler(event, context): path = '/mnt/test/efstest.txt' with open(path) as f: print(f.read()) s = 'test message' with open(path, mode='w') as f: f.write(s) with open(path) as f: print(f.read())
993、990という謎ユーザー/グループで作成されることが分かりました。
[root@ip-10-0-0-9 test]# ll 合計 16 -rw-rw-r-- 1 993 990 12 9月 5 06:19 efstest.txt
Python以外では試していないため、どのランタイムでもこのユーザーになるのかは不明です。特段理由がなければPOSIXユーザーは指定しておくべきです。冒頭で紹介したLambdaで設定する際の参考情報を再掲します。
Lambda 関数を使用してファイルシステムをマウントするための正しい EFS アクセスポイント構成を作成するにはどうすればよいですか?
Lambda 関数のファイルシステムアクセスの設定-ファイルシステムとアクセスポイントの設定
EFSのファイルシステムポリシー
今回の話から少し逸れますがEFSへのアクセス制御としてファイルシステムポリシーというのもあります。デフォルトの未設定ではフルアクセス権限になります。
ファイルシステムにユーザー設定の IAM ポリシーがない場合、EFS は、ファイルシステムマウントターゲットを使用してファイルシステムに接続できるすべてのクライアントへのフルアクセスを許可するデフォルトのポリシーを使用します。ファイルシステムにユーザー設定の IAM ポリシーがある場合、関数の実行ロールには正しい
elasticfilesystem
許可が必要です。
ファイルシステムポリシー使用したアクセスポイントへのアクセス制御についてはサンプルが用意されています。
ブログ記事もありますので、こちらも参考になります。
最後に
一通り試して、今回のEFSアクセスポイントのオプションは設定しておいた方がいいなと思いました。POSIXユーザーを指定することで、接続元のユーザー権限を意識する必要がなくなるのは楽だし安全です。EFSのデフォルトがno_root_squashで動作するため、ファイルシステムポリシーと組み合わせて思わぬ事故やセキュリティリスクを防ぐことにも役立ちそうです。とはいえ、接続元のNFSクライアントや接続先のEFSで適切な権限設定がされていたり、接続元が限定的であれば必須とまではいかなそうです。